home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac100% 1998 November
/
MAC100-1998-11.ISO.7z
/
MAC100-1998-11.ISO
/
オンラインソフト定点観測
/
ユーティリティ
/
Mops 3.2.sea
/
Mops 3.2
/
Mops source
/
PPC source
/
cg-inst_ref
< prev
next >
Wrap
Text File
|
1998-04-20
|
18KB
|
752 lines
marker m__cg-inst/ref
PPC?
[IF]
false constant debug?
[ELSE]
false constant debug?
[THEN]
(*
INSTRUCTION_CLASS is just used as a convenient way of compiling an
instruction. The fields can be set up individually, and we can print
it when we compile it, etc. We simplify the reg field terminology a
bit, and just use rA and rB as the source regs, and rD as the destination.
(This differs from the "real" definition of the logical ops which use rA
as the destination, for some unfathomable reason. But we kludge around
that before generating the instruction.)
*)
:class INSTRUCTION_CLASS super{ object }
record
{ ubyte rA ¥ 1st source
ubyte rB ¥ 2nd source
ubyte rC ¥ 3rd source (fmadd etc.)
ubyte rD ¥ destination
ubyte inst_type
ubyte primOp ¥ primary opcode
uint secOp ¥ secondary opcode
ubyte shift#
public
ubyte maskBegin
ubyte maskEnd
bool setCR?
bool lit?
bool update? ¥ for load/stores: use update mode?
bool complB? ¥ for logicals: complement B operand - and -> andc etc.
bool complResult? ¥ for logicals: and -> nand etc.
bool CR_op? ¥ for logicals: condition reg op?
bool use_CTR? ¥ for branches: use count reg?
bool use_cond? ¥ use condition?
bool branchOn1? ¥ branch on CR bit 1 or 0?
bool kludgeShiftCnt? ¥ true if 6-bit shift cnt (which has to be split)
bool shifted? ¥ true if this is a shifted variant (addis etc.)
var lit ¥ allowing 32 bits 'cause we need 24 for branches
}
:m >rA: inline{ put: rA} ;m
:m >rB: inline{ put: rB} ;m
:m >rC: inline{ put: rC} ;m
:m >rD: inline{ put: rD} ;m
:m >lit: inline{ put: lit set: lit?} ;m
:m >primOp: inline{ put: primOp} ;m
:m >secOp: inline{ put: secOp} ;m
:m >type: inline{ put: inst_type} ;m
:m >shift: put: shift# shiftType put: inst_type ;m
:m kludgeShiftCnt: set: kludgeShiftCnt? ;m
:m INVERT: get: branchOn1? not put: branchOn1? ;m
private
:m swapAB: ¥ subtract, I think for historical reasons, is "subtract from"
¥ and the operands are the other way around to the Forth convention.
¥ Note this doesn't apply to floating point!
get: rA get: rB put: rA put: rB
;m
public
¥ setop: maps our internal opcodes to the corresponding PPC instruction codes,
¥ and sets primOp, secOp and inst_type appropriately.
¥ Note fetches and stores have the PPC codes set directly from the OD class,
¥ and don't come here.
:m SETOP: { opType subtype -- inst_type }
clear: lit?
opType
SELECT[ otAdd ]=> arithType 31 266
[ otSub ]=> arithType 31 40 swapAB: self
[ otAddc ]=> arithType 31 10
[ otAdde ]=> arithType 31 138
[ otAddze ]=> arithType 31 202
[ otAddme ]=> arithType 31 234
[ otSubfc ]=> arithType 31 8 swapAB: self
[ otSubfe ]=> arithType 31 136 swapAB: self
[ otSubfze ]=> arithType 31 200 clear: rB
[ otSubfme ]=> arithType 31 232 clear: rB
[ otMUL ]=> arithType 31
64bit? if 233 else 235 then
[ otMULH ]=> arithType 31
64bit? if 73 else 75 then
[ otUMULH ]=> arithType 31
64bit? if 9 else 11 then
[ otDIV ]=> arithType 31
64bit? if 489 else 491 then
[ otUDIV ]=> arithType 31
64bit? if 457 else 459 then
¥ floating point:
[ otFADD ]=> arithType 63 21 ¥ fadd
[ otFSUB ]=> arithType 63 20 ¥ fsub
[ otFMUL ]=> arithType 63 25 ¥ fmul
¥ fmuld uses the rC field as the second operand, like fmadd, which makes
¥ sense to the hardware which treats it like an fmadd with an add of 0.
get: rB put: rC clear: rB
[ otFMADD ]=> arithType 63
subtype
SELECT[ 0 ]=> 29 ¥ fmadd
[ 1 ]=> 28 ¥ fmsub
[ 2 ]=> 30 ¥ fnmsub
DEFAULT=>
cr .h ." undef subtype for fmadd" 1 die
]SELECT
get: rB get: rC put: rB put: rC
[ otFDIV ]=> arithType 63 18 ¥ fdiv
¥ FP monadics - these use the rB field as the (single) source operand
[ $ 54 ]=> arithType 63 264 ¥ fabs
get: rA put: rB clear: rA
[ $ 55 ]=> arithType 63 40 ¥ fnegate
get: rA put: rB clear: rA
¥ logicals have a lot of options:
[ otAnd ]=> logicalType
get: CR_op?
IF 19 get: complResult?
IF 225 ¥ crnand
ELSE get: complB?
IF 129 ¥ crandc
ELSE 257 ¥ crand
THEN
THEN
ELSE
31 get: complResult?
IF 476 ¥ nand
ELSE get: complB?
IF 60 ¥ andc
ELSE 28 ¥ and
THEN
THEN
THEN
[ otOr ]=> logicalType
get: CR_op?
IF 19 get: complResult?
IF 33 ¥ crnor
ELSE get: complB?
IF 417 ¥ crorc
ELSE 449 ¥ cror
THEN
THEN
ELSE
31 get: complResult?
IF 124 ¥ nor
ELSE get: complB?
IF 412 ¥ orc
ELSE 444 ¥ or
THEN
THEN
THEN
[ otXor ]=> logicalType
get: CR_op?
IF 19 get: complResult?
IF 289 ¥ creqv
ELSE 193 ¥ crxor
THEN
ELSE
31 get: complResult?
IF 284 ¥ eqv
ELSE 316 ¥ xor
THEN
THEN
[ otCMP ]=> cmpType 31 0
[ otUCMP ]=> cmpType 31 32
[ otFPcmp ]=> cmpType 63 0
subType 4 and
IF ¥ it's an FP comparison with zero - there's no special
¥ instructions for this, so we keep zero in fpr14.
14 put: rB
THEN
¥ [ otFPcmpU ]=> cmpType 63 32 ¥ if we implement unordered
[ otTrap ]=> arithType 31 64bit? if 68 else 4 then
subType put: rD ¥ this is actually the TO field
[ otNEG ]=> arithType 31 104
[ otNOT ]=> logicalType
get: rA put: rB ¥ we do NOT with a nand
¥ or crnand, with rA = rB
get: CR_op?
IF
19 225 ¥ crnand
ELSE
31 476 ¥ nand
THEN
DEFAULT=> cr .h ." undef op passed to setop" 1 die
]SELECT
put: secOp put: primOp dup put: inst_type
;m
¥ setLiteralOp does the same for literal operations.
:m SETLITERALOP: { opType subtype -- inst_type }
set: lit? clear: shifted?
opType
SELECT[ otAdd ]=> arithType 14
¥ subtract immed doesn't exist - we use add immed
[ otAddc ]=> arithType 12 ¥ addic
[ otSubfc ]=> arithType 8 ¥ subfic
[ otMul ]=> arithType 7
¥ divide immed doesn't exist either!
[ otAnd ]=> logicalType 28
[ otOr ]=> logicalType 24
[ otXor ]=> logicalType 26
[ otCMP ]=> cmpType 11
[ otUCMP ]=> cmpType 10
[ otTrap ]=> arithType 64bit? if 2 else 3 then
subType put: rD ¥ this is actually the TO field
¥ otAdde and otSubfe can come here with a literal operand - only 0 and -1
¥ are legal (this should be OK as these only come from internal inline
¥ definitions). We then generate addze, addme etc. as appropriate.
[ otAdde ]=> get: lit dup
NIF drop 202 ¥ addze
ELSE
-1 =
IF 234 ¥ addme
ELSE ." otAdde with illegal lit " get: lit .
1 die
THEN
THEN
put: secop clear: lit?
arithType 31
[ otSubfe ]=> get: lit dup
NIF drop 200 ¥ subfze
ELSE
-1 =
IF 232 ¥ subfme
ELSE ." otSubfe with illegal lit " get: lit .
1 die
THEN
THEN
put: secop clear: lit?
arithType 31
DEFAULT=> cr .h ." undef op passed to setLiteralOp" 1 die
]SELECT
put: primOp dup put: inst_type
;m
:m PRINT:
." type " print: inst_type cr
." primOp " print: primOp cr
." secOp " print: secOp cr
get: inst_type branchType =
IF ." displ " print: lit cr
ELSE
." setCR? " print: setCR? cr
." rA " print: rA cr
get: lit?
NIF ." rB " print: rB cr
THEN
." rD " print: rD cr
get: lit?
IF ." lit "
print: lit 4 spaces base hex print: lit -> base
THEN
." maskBegin " print: maskBegin cr
." maskEnd " print: maskEnd cr
." update? " print: update? cr
." complB? " print: complB? cr
." complResult? " print: complResult? cr
." CR_op? " print: CR_op? cr
THEN
;m
:m COMPILE: { ¥ tmp branchOp updBit -- }
(* first we make the necessary adjustments depending on the instruction type. For
the more unusual types we do the whole job then EXIT, while for the more normal
types we set things up then fall through to the generic compiling code.
*)
get: inst_type
SELECT[ logicalType ]=>
(* logical GPR instrns, for historical reasons, use the rA field
as the destination! We just fix it here at the last moment
by swapping the rA and rD fields.
*)
get: CR_op?
NIF get: rA get: rD put: rA put: rD THEN
get: lit? get: shifted? and IF get: primOp 1+ put: primOp THEN
[ arithType ]=>
[ cmpType ]=> get: rD 2 << put: rD ¥ cr field#
[ loadStoreType ]=> false -> updBit
get: update?
IF get: primOp 58 ( ld ) =
get: primOp 62 ( std ) = or
IF 1 +: lit
ELSE ¥ assume lwz, stw, lfd or stfd
get: primOp 1+ put: primOp
THEN
THEN
[ branchType ]=> get: primOp 26 << -> tmp
get: primOp 18 = ¥ unconditional?
IF
get: lit $ 03FFFFFF and or> tmp
ELSE
get: use_cond? not $ 10 and -> branchOp
get: use_CTR? not 4 and or> branchOp
get: use_cond?
IF get: branchOn1? 8 and or> branchOp
get: rA 16 << or> tmp
THEN
branchOp 21 << or> tmp
get: lit $ FFFF and or> tmp
THEN
tmp code, EXIT
[ shiftType ]=> 64bit?
IF db
ELSE
get: primOp 26 << -> tmp
get: secOp
NIF ¥ this must be a rotate and mask
get: maskBegin 6 << or> tmp
get: maskEnd 1 << or> tmp
ELSE
get: secOp 2* or> tmp
THEN
¥ shifts have rA as the destination, like logicals
¥ - so our rA is really rS.
get: rA 21 << or> tmp
get: rD 16 << or> tmp
get: shift# 11 << or> tmp
get: setCR? 1 and or> tmp
tmp code, EXIT
THEN
DEFAULT=> drop
]SELECT
get: primOp 26 << -> tmp
get: rA 16 << or> tmp
get: rD 21 << or> tmp
get: lit?
IF
get: lit $ FFFF and or> tmp
ELSE
get: rB 11 << or> tmp
get: rC 6 << or> tmp
get: secOp 2* or> tmp
¥ finally we set Rc bit if necessary - note the only immediate instruction
¥ that sets CR0 is andi, which always does it, without using the Rc
¥ bit (which is part of the immediate field anyway).
get: setCR? 1 and or> tmp
THEN
debug? if
cr ." compiling at " CDP .h cr
print: self cr
." instruction: " tmp .h cr
then
tmp code,
;m
:m CLEAR:
^base ['] instruction_class ivarlen erase
arithType put: inst_type
(*
clear: rA clear: rB clear: rD
arithType put: inst_type
clear: primOp clear: secOp clear: lit
clear: setCR? clear: lit? clear: update?
clear: complB? clear: complResult? clear: CR_op?
clear: use_CTR? clear: use_cond? clear: branchOn1?
clear: kludgeShiftCnt? clear: shifted?
*)
;m
;class
instruction_class INSTRN
instruction_class BRANCH_INSTRN
PPC? not [IF] branchType >type: branch_instrn [THEN]
0 value startCDP
0 value deltaCDP
forward ALLOCATE_GPR
forward ALLOCATE_FPR
forward ALLOCATE_CR
forward FREE_GPR
forward FREE_FPR
forward FREE_CR
forward DEL_GPR
forward DEL_FPR
forward DEL_CR
forward ?CLEAR_GPR
forward ?CLEAR_FPR
forward ?CLEAR_CR
forward USE_GPR
forward USE_FPR
forward USE_CR
forward SET_CR0
forward GPR_CDP
forward FPR_CDP
forward CR_CDP
forward REG_CHANGED
forward UPDATE_CDPs
¥ forward UPDATE_opCDPs
forward FIX_CONTAINING_LOOP
forward UPDATE_REFS
forward DEFER_STORE
forward HOIST_LATER
¥ forward STORE_ALL_PENDING
(*
Class REFERENCE defines a reference to an OD (see below) or a short
literal value (we try to handle these at compile time if possible).
Our compile-time stack is an array of REFERENCEs.
Note: at the moment I'm just planning to track as much of the stack
as will fit in the regs allocated for general operands. I could allow
more, but I'd need to keep a full OD for each stack cell rather than
just a reg reference. Also reg spills would be problematic, as would
be making sure the OD in the reg list and the corresponding one in the
stack always agreed. I think the problems wouldn't be worth the trouble,
especially as I don't think the number of valid stack cells that I can
track will usually be very many, because of word calls requiring
normalization of the stack.
*)
¥ Reference types:
enum { noRef gprRef fprRef crRef litRef pullRef }
:class REFERENCE super{ object }
record
{
ubyte REFTYPE
union
{ ubyte REG#
var LITVAL
public
record
{ ubyte FIELD# ¥ note: same byte as REG#. We rely on this!
ubyte BIT#
bool 1_is_true?
}
end_public
}
}
:m PRINT:
get: refType
SELECT[ gprRef ]=> ." gpr# " print: reg#
[ fprRef ]=> ." fpr# " print: reg#
[ crRef ]=> ." cr fld# " print: field#
." bit# " print: bit#
." 1_is_true? " print: 1_is_true?
[ litRef ]=> ." lit "
print: litval 4 spaces base hex print: litval -> base
[ pullRef ]=> ." pull"
DEFAULT=> drop ." noRef"
]SELECT
cr
;m
:m REFTYPE: get: refType ;m
:m >REFTYPE: put: refType ;m
:m GPR: gprRef get: refType <> IF cr .id: self cr
." not a GPR ref" cr
print: self 1 die
THEN
get: reg# ;m
:m FPR: fprRef get: refType <> IF cr .id: self cr
." not a FPR ref" cr
print: self 1 die
THEN
get: reg# ;m
:m CR: crRef get: refType <> IF cr .id: self cr
." not a CR ref" cr
print: self 1 die
THEN
get: field# ;m
:m REG: inline{ get: reg#} ;m
:m BIT#: inline{ get: bit#} ;m
:m 1_is_true?: inline{ get: 1_is_true?} ;m
:m LIT: litRef get: refType <> IF .id: self cr
." not a lit ref" 1 die
THEN
get: litval ;m
:m CLEAR:
^base ['] reference ivarlen erase ;m
:m >REG: inline{ put: reg#} ;m
:m >GPR: clear: self gprRef put: refType put: reg# ;m
:m >FPR: clear: self fprRef put: refType put: reg# ;m
:m >CR: clear: self crRef put: refType put: field# ;m
:m >CONDITION: { opcode -- }
opcode 1 and put: 1_is_true?
opcode 4 >> put: bit#
;m
:m >LIT: clear: self litRef put: refType put: litval ;m
:m >PULL: clear: self pullRef put: refType ;m
:m ->: ¥ ( ^ref -- )
^base
['] reference ivarlen ¥ note length is 6 on 68k, but 8 on PPC
¥ due to alignment
aligned_move ;m
¥ Careful - the next 3 methods assume a reference is 6 bytes long!
:m =?: { ^ref -- b }
false
¥ get: refType noRef = ?EXIT ¥ "noRef" can't match, no matter what
^ref ^base
['] reference ivarlen
(s=) 0EXIT
drop true
;m
:m STACK: ¥ ( -- <ref-info> )
^base @
^base 4+ @
^base 6 + w@ ;m
:m UNSTACK: ¥ ( <ref-info> -- )
^base 6 + w!
^base 4+ !
^base ! ;m
:m MARK_USE: ¥ ( CDPtoUse -- ) Marks the OD with a use at the given
¥ CDP position.
get: reg#
get: refType
SELECT[ gprRef ]=> use_gpr
[ fprRef ]=> use_fpr
[ crRef ]=> use_cr
DEFAULT=> ( nothing to do ) 2drop drop
]SELECT
;m
:m ALLOCATE: ¥ if this is a reg, allocates it.
get: refType
SELECT[ gprRef ]=> get: reg# allocate_gpr
[ fprRef ]=> get: reg# allocate_fpr
[ crRef ]=> get: reg# allocate_cr
DEFAULT=> ( nothing to do ) drop
]SELECT
;m
:m FREE: ¥ if this is a reg, frees it.
debug? if ." freeing ref:" cr print: self then
get: refType
SELECT[ gprRef ]=> get: reg# free_gpr
[ fprRef ]=> get: reg# free_fpr
[ crRef ]=> get: reg# free_cr
DEFAULT=> ( nothing to do ) drop
]SELECT
;m
:m DELETE: ¥ if this is a reg, we delete it if safe to do so.
¥ Then whatever it was, we clear the ref. We assume
debug? if ." deleting ref:" cr print: self then
get: refType
SELECT[ gprRef ]=> get: reg# del_gpr
[ fprRef ]=> get: reg# del_fpr
[ crRef ]=> get: reg# del_cr
DEFAULT=> ( nothing to do ) drop
]SELECT
clear: self
;m
:m opCDP: ¥ if this is a reg, returns the CDP location of the associated
¥ operation, otherwise -1.
get: refType
SELECT[ gprRef ]=> get: reg# gpr_CDP
[ fprRef ]=> get: reg# fpr_CDP
[ crRef ]=> get: reg# cr_CDP
DEFAULT=> drop -1
]SELECT
;m
;class
reference tmpRef1
reference tmpRef2
reference tmpRef3
reference tmpRef4
:class CSTACK_CLASS super{ array }
int SIZE
:m PUSH: ( n -- )
get: size to: self 1 +: size
;m
:m POP: ( -- n )
get: size 0<= IF ." control stack underflow" 1 die THEN
-1 +: size
get: size at: self
;m
:m STK: { cell# -- n }
get: size cell# - at: self ;m
:m SIZE: get: size ;m
:m >SIZE: put: size ;m
:m UPDATE: { ¥ thisCDP -- }
get: size 0EXIT
get: size
FOR i at: self -> thisCDP
thisCDP startCDP u>=
IF deltaCDP ++> thisCDP
thisCDP i to: self
THEN
NEXT
;m
:m MATCH?: { n -- index T | -- F }
false
get: size 0
DO i at: self n =
IF drop i true LEAVE
THEN
LOOP
;m
:m PRINTALL:
." depth: " get: size . cr
get: size
IF get: size
FOR ?pause i at: self .h cr NEXT
THEN
;m
;class
¥ see ppc3 for the definition of these flag bytes...
:class CSTACK_FLAGS_CLASS super{ bArray }
int SIZE
:m SIZE: get: size ;m
:m >SIZE: put: size ;m
:m PUSH: ( n -- )
get: size to: self 1 +: size
;m
:m POP: ( -- n )
get: size 0<= IF ." control stack flags underflow" 1 die THEN
-1 +: size
get: size at: self
;m
:m STK: { cell# -- n }
get: size cell# - at: self ;m
:m PRINTALL:
." depth: " get: size . cr
get: size
IF get: size
FOR ?pause i at: self .h cr NEXT
THEN
;m
;class
128 cstack_class CONTROL_STK
128 cstack_flags_class CONTROL_FLAGS